The upload mechanism in SFtp is provided by the SFtpFile.CopyTo method. The method
Validates the supplied parameters by checking for null for example.
Makes sure the upload makes sense by making sure the source exists, isn't the same as the destination, and other checks.
Performs the upload by copying the data from the source to the destination.
Applies the properties like dates, file attributes from the source file to the destination file.
In some scenarios, not all of these steps are desirable. For example, some SFtp servers remove files as soon as they are uploaded. This can cause problems with the last step of the upload procedure as the destination file might have disappeared before the properties can be applied.
In these cases, it might be best to avoid using the CopyTo method and perform uploads manually. This allows an application to focus on the data upload only and avoid operations the server cannot handle.
A manual upload is performed by opening streams for both the source and destination files and copying data read from the source stream to the destination stream in a loop until there is no more data to read. The amount of data read from the source in each iteration can be carefully chosen with the ComputeStreamBufferSize Method to generate the least overhead.
using System;
using System.IO;
using Xceed.SSH.Client;
using Xceed.SSH.Protocols;
using Xceed.SSH.Core;
using Xceed.FileSystem;
namespace DocumentationExamples.SSH
{
publicclass ManualCopyTo
{
publicstaticvoid Example()
{
string host = "sftptest.dreamhosters.com";
string username = "snippet_sftp";
string password = "9MNfGgSx";
using( SSHClient ssh = new SSHClient() )
{
ssh.Connect( host );
ssh.Authenticate( username, password );
// Start a SFtp session from the SSH client
using( SFtpSession sftp = new SFtpSession( ssh ) )
{
// Select a local file
AbstractFile sourceFile = new DiskFile( @"SomeFile.dat" );
// Select a remote destination folder
AbstractFolder destinationFolder = new SFtpFolder( sftp, "SomeFolder" );
// Select the destination file in the destination folder using the name of the source file
AbstractFile destinationFile = destinationFolder.GetFile( sourceFile.Name );
if( !sourceFile.Exists )
thrownew InvalidOperationException( "Source file does not exist." );
if( sourceFile.IsSameAs( destinationFile ) )
thrownew InvalidOperationException( "Cannot copy a file unto itself." );
// Open the source file for reading
using( Stream sourceStream = sourceFile.OpenRead() )
{
Stream destinationStream = null;
try
{
// If the destination file already exists
if( destinationFile.Exists )
{
// Open it for writing, overwriting its previous contents
destinationStream = destinationFile.OpenWrite( true );
}
else
{
// Create it and open it for writing in one operation
destinationStream = destinationFile.CreateWrite();
}
/* SSH has an overhead and several rules that define a maximum logical packet
size.
We are free to use any reasonable buffer size we want and it will work.
However, using a value too small will generate more overhead than needed.
Using a value too large will force the component to split the data into
several packets and increase overhead as well.
SFtpSession has a method that computes the optimal buffer size for the
SFtp stream. It takes into account the effective overhead packets will have
and computes a value that will make it so that every call to Stream.Write()
will end up creating the biggest SSH packet allowed by the server that does
not generate extra overhead.
This provides the best throughput in a file transfer. */int bufferSize = sftp.ComputeStreamBufferSize( destinationStream );
// Create a buffer for the streams
byte[] buffer = newbyte[ bufferSize ];
int read;
// While we have data to read from the source stream
while( ( read = sourceStream.Read( buffer, 0, bufferSize ) ) > 0 )
{
// Write the data to the destination stream
destinationStream.Write( buffer, 0, read );
}
}
finally
{
// If we have a destination stream
if( destinationStream != null )
{
// Close it
destinationStream.Close();
}
}
}
}
}
}
}
}
Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports Xceed.SSH.Client
Imports Xceed.SSH.Protocols
Imports Xceed.SSH.Core
Imports Xceed.FileSystem
Namespace DocumentationExamples.SSH
PublicClass ManualCopyTo
PublicSharedSub Example()
Dim host AsString = "sftptest.dreamhosters.com"Dim username AsString = "snippet_sftp"Dim password AsString = "9MNfGgSx"Using ssh AsNew SSHClient()
ssh.Connect(host)
ssh.Authenticate(username, password)
' Start a SFtp session from the SSH client
Using sftp AsNew SFtpSession(ssh)
' Select a local file
Dim sourceFile As AbstractFile = New DiskFile("SomeFile.dat")
' Select a remote destination folder
Dim destinationFolder As AbstractFolder = New SFtpFolder(sftp, "SomeFolder")
' Select the destination file in the destination folder using the name of the source file
Dim destinationFile As AbstractFile = destinationFolder.GetFile(sourceFile.Name)
If (Not sourceFile.Exists) ThenThrowNew InvalidOperationException("Source file does not exist.")
EndIfIf sourceFile.IsSameAs(destinationFile) ThenThrowNew InvalidOperationException("Cannot copy a file unto itself.")
EndIf' Open the source file for reading
Using sourceStream As Stream = sourceFile.OpenRead()
Dim destinationStream As Stream = NothingTry' If the destination file already exists
If destinationFile.Exists Then' Open it for writing, overwriting its previous contents
destinationStream = destinationFile.OpenWrite(True)
Else' Create it and open it for writing in one operation
destinationStream = destinationFile.CreateWrite()
EndIf' SSH has an overhead and several rules that define a maximum logical packet
' size.
'
' We are free to use any reasonable buffer size we want and it will work.
' However, using a value too small will generate more overhead than needed.
' Using a value too large will force the component to split the data into
' several packets and increase overhead as well.
'
' SFtpSession has a method that computes the optimal buffer size for the
' SFtp stream. It takes into account the effective overhead packets will have
' and computes a value that will make it so that every call to Stream.Write()
' will end up creating the biggest SSH packet allowed by the server that does
' not generate extra overhead.
'
' This provides the best throughput in a file transfer.
Dim bufferSize AsInteger = sftp.ComputeStreamBufferSize(destinationStream)
' Create a buffer for the streams
Dim buffer(bufferSize - 1) AsByteDim read AsInteger' While we have data to read from the source stream
read = sourceStream.Read(buffer, 0, bufferSize)
DoWhile read > 0
' Write the data to the destination stream
destinationStream.Write(buffer, 0, read)
read = sourceStream.Read(buffer, 0, bufferSize)
LoopFinally' If we have a destination stream
If destinationStream IsNotNothingThen' Close it
destinationStream.Close()
EndIfEndTryEndUsingEndUsingEndUsingEnd SubEnd ClassEnd Namespace